package com.gutsyzhan.bilibili.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.gutsyzhan.bilibili.constant.UserConstant;
import com.gutsyzhan.bilibili.dao.RefreshTokenDao;
import com.gutsyzhan.bilibili.dao.UserDao;
import com.gutsyzhan.bilibili.dao.UserInfoDao;
import com.gutsyzhan.bilibili.domain.PageResult;
import com.gutsyzhan.bilibili.domain.User;
import com.gutsyzhan.bilibili.domain.UserInfo;
import com.gutsyzhan.bilibili.domain.auth.RefreshToken;
import com.gutsyzhan.bilibili.exception.ConditionException;
import com.gutsyzhan.bilibili.service.UserAuthService;
import com.gutsyzhan.bilibili.service.UserService;
import com.gutsyzhan.bilibili.util.MD5Util;
import com.gutsyzhan.bilibili.util.RSAUtil;
import com.gutsyzhan.bilibili.util.StrUtil;
import com.gutsyzhan.bilibili.util.TokenUtil;
import com.mysql.jdbc.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

@Service
public class UserServiceImpl implements UserService {
    @Resource
    private UserDao userDao;
    @Resource
    private UserInfoDao userInfoDao;

    @Resource
    private UserAuthService userAuthService;

    @Resource
    private RefreshTokenDao refreshTokenDao;

    @Override
    public void addUser(User user) {
        String phone = user.getPhone();
        StrUtil.StrIsNullOrEmpty(phone, "手机号不能为空！");
        User userByPhone = getUserByPhone(phone);
        if(userByPhone != null){
            throw new ConditionException("该手机号已经注册!");
        }
        Date now = new Date();
        //盐值为当前时间的时间戳
        String salt = String.valueOf(now.getTime());
        //获取前端传递的密码，注意这个密码已经使用RSA公钥进行加密了
        String password = user.getPassword();
        String rowPassword;
        try{
            //使用RAS解密前端传来的密码
            rowPassword = RSAUtil.decrypt(password);
        }catch (Exception e){
            throw new ConditionException("密码解密失败");
        }
        //获取MD5加密后的密码
        String md5Password = MD5Util.sign(rowPassword, salt, "UTF-8");
        //更新User对象的属性
        user.setPassword(md5Password);
        user.setSalt(salt);
        user.setCreateTime(now);
        user.setUpdateTime(now);
        //将User保存到数据库
        userDao.addUser(user);
        //给用户新建UserInfo信息，并设置默认信息
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(user.getId());
        userInfo.setNick(UserConstant.DEFAULT_NICK);
        userInfo.setBirth(UserConstant.DEFAULT_BIRTH);
        userInfo.setGender(UserConstant.GENDER_UNKNOWN);
        userInfo.setCreateTime(now);
        userInfo.setUpdateTime(now);
        userInfo.setSign(UserConstant.DEFAULT_SIGN);
        //将UserInfo保存到数据库
        userInfoDao.addUser(userInfo);
        //添加用户默认权限角色
        userAuthService.addUserDefaultRole(user.getId());
    }

    public User getUserByPhone(String phone){
        return userDao.getUserByPhone(phone);
    }

    @Override
    public String login(User user) throws Exception {
        String phone = user.getPhone() == null ? "":user.getPhone();
        String email = user.getEmail() == null ? "":user.getEmail();
        if(StringUtils.isNullOrEmpty(phone) && StringUtils.isNullOrEmpty(email)){
            throw new ConditionException("登录账号不得为空!");
        }
        User userByPhoneOrEmail = userDao.getUserByPhoneOrEmail(phone, email);
        if(userByPhoneOrEmail == null){
            throw new ConditionException("当前用户未注册!");
        }
        //从数据库中查询盐值
        String salt = userByPhoneOrEmail.getSalt();
        //获取前端传递的密码，注意这个密码已经使用RSA公钥进行加密了
        String password = user.getPassword();
        String rowPassword;
        try{
            //使用RAS解密前端传来的密码
            rowPassword = RSAUtil.decrypt(password);
        }catch (Exception e){
            throw new ConditionException("密码解密失败");
        }
        //获取MD5加密后的密码
        String md5Password = MD5Util.sign(rowPassword, salt, "UTF-8");
        //数据库中查询的密码
        String dbPassword = userByPhoneOrEmail.getPassword();
        //对比密码
        if(!Objects.equals(md5Password, dbPassword)){
            throw new ConditionException("密码错误");
        }
        //生成用户令牌
        String token = TokenUtil.generateAccessToken(userByPhoneOrEmail.getId());
        return token;
    }

    @Override
    public User getUserInfo(Long userId) {
        User user = userDao.getUserById(userId);
        UserInfo userInfo = userInfoDao.getUserByUserId(userId);
        user.setUserInfo(userInfo);
        return user;
    }

    @Override
    public void updateUsers(User user) throws Exception {
        Date now = new Date();
        Long id = user.getId();
        User dbUser = userDao.getUserById(id);
        if(dbUser == null){
            throw new ConditionException("用户不存在!");
        }
        //校验用户输入的密码信息
        if(!StringUtils.isNullOrEmpty(user.getPassword())){
            //解密用户输入的密码信息
            String rowPassword = RSAUtil.decrypt(user.getPassword());
            //将用户输入的密码进行MD5加密
            String md5Password = MD5Util.sign(rowPassword, dbUser.getSalt(), "UTF-8");
            //更新用户密码
            user.setPassword(md5Password);
        }
        user.setUpdateTime(now);
        userDao.updateUsers(user);
    }

    @Override
    public void updateUserInfos(UserInfo userInfo) {
        userInfo.setUpdateTime(new Date());
        userInfoDao.updateUserInfos(userInfo);
    }

    @Override
    public User getUserById(Long id) {
        return userDao.getUserById(id);
    }

    @Override
    public List<UserInfo> getUserInfoByUserIds(Set<Long> userIds) {
        return userInfoDao.getUserInfoByUserIds(userIds);
    }

    @Override
    public PageResult<UserInfo> pageListUserInfos(JSONObject params) {
        Integer pageNo = params.getInteger("pageNo");
        Integer pageSize = params.getInteger("pageSize");
        params.put("start", (pageNo-1)*pageSize);
        params.put("limit", pageSize);
        Integer total = userInfoDao.pageCountUserInfos(params);
        List<UserInfo> userInfoList = new ArrayList<>();
        if(total > 0){
            userInfoList = userInfoDao.pageListUserInfos(params);
        }
        return new PageResult<>(total, userInfoList);
    }

    @Override
    public Map<String, Object> loginForDts(User user) throws Exception {
        String phone = user.getPhone() == null ? "":user.getPhone();
        String email = user.getEmail() == null ? "":user.getEmail();
        if(StringUtils.isNullOrEmpty(phone) && StringUtils.isNullOrEmpty(email)){
            throw new ConditionException("登录账号不得为空!");
        }
        User userByPhoneOrEmail = userDao.getUserByPhoneOrEmail(phone, email);
        if(userByPhoneOrEmail == null){
            throw new ConditionException("当前用户未注册!");
        }
        //从数据库中查询盐值
        String salt = userByPhoneOrEmail.getSalt();
        //获取前端传递的密码，注意这个密码已经使用RSA公钥进行加密了
        String password = user.getPassword();
        String rowPassword;
        try{
            //使用RAS解密前端传来的密码
            rowPassword = RSAUtil.decrypt(password);
        }catch (Exception e){
            throw new ConditionException("密码解密失败");
        }
        //获取MD5加密后的密码
        String md5Password = MD5Util.sign(rowPassword, salt, "UTF-8");
        //数据库中查询的密码
        String dbPassword = userByPhoneOrEmail.getPassword();
        //对比密码
        if(!Objects.equals(md5Password, dbPassword)){
            throw new ConditionException("密码错误");
        }
        Long userId = userByPhoneOrEmail.getId();
        //生成用户accessToken
        String accessToken = TokenUtil.generateAccessToken(userId);
        //生成用户refreshToken
        String refreshToken = TokenUtil.generateRefreshToken(userId);
        //refreshToken需要保存到数据库中
        //查询refreshToken是否存在，不存在则直接新增，否则直接更新
        RefreshToken dbRefreshToken = refreshTokenDao.getRefreshToken(userId, refreshToken, UserConstant.DELETE_FLAG);
        if(dbRefreshToken != null){
            //修改
            refreshTokenDao.updateRefreshToken(userId, refreshToken, UserConstant.NORMAL_FLAG, new Date());
        }else{
            //新增
            refreshTokenDao.addRefreshToken(userId, refreshToken, new Date());
        }
        Map<String, Object> map = new HashMap<>();
        map.put("accessToken", accessToken);
        map.put("refreshToken", refreshToken);
        return map;
    }

    @Override
    public void logout(Long userId, String refreshToken) {
        //逻辑删除t_refresh_token表中的refreshToken
        refreshTokenDao.updateRefreshToken(userId, refreshToken, UserConstant.DELETE_FLAG, new Date());
    }

    @Override
    public String refreshAccessToken(Long userId, String refreshToken) throws Exception {
        RefreshToken dbRefreshToken = refreshTokenDao.getRefreshToken(userId, refreshToken, UserConstant.NORMAL_FLAG);
        if(dbRefreshToken == null){
            throw new ConditionException("555", "token过期!");
        }else{
            //生成用户accessToken
            return TokenUtil.generateAccessToken(userId);
        }
    }

    @Override
    public List<UserInfo> batchGetUserInfoByUserIds(Set<Long> userIdSet) {
        return userDao.batchGetUserInfoByUserIds(userIdSet);
    }
}
